package logger

import (
	"fmt"
	"strings"
	"sync"
	"time"
)

type iLoggingService interface {
	Logf(f string, args ...interface{})
	AllLogs() []string
	Verbose(bool)
}

type tLoggingService struct {
	mutex *sync.Mutex

	logs     []string
	capacity int
	rindex   int
	windex   int
	verbose  bool
}

var gMaxLogs = 10_000
var gEmptyString = ""

func newLoggingService() iLoggingService {
	return &tLoggingService{
		mutex: new(sync.Mutex),

		logs: make([]string, gMaxLogs*2),
		//logs: make([]string, 0),
		capacity: gMaxLogs,
		rindex:   0,
		windex:   0,
		verbose:  true,
	}
}

func (me *tLoggingService) size() int {
	return me.windex - me.rindex
}

func (me *tLoggingService) Verbose(v bool) {
	me.verbose = v
}

func (me *tLoggingService) Logf(f string, args ...interface{}) {
	log := fmt.Sprintf(f, args...)

	me.mutex.Lock()
	//me.logs = append(me.logs, log)
	me.ensureSpace()
	me.logs[me.windex] = log
	me.windex++
	me.mutex.Unlock()

	if me.verbose {
		fmt.Println(log)
	}
}

func (me *tLoggingService) ensureSpace() {
	for me.size() >= me.capacity {
		// dequeue head items
		me.logs[me.rindex] = gEmptyString
		me.rindex++
	}

	if me.rindex >= me.capacity {
		// move data to offset 0
		for i, n := 0, me.size(); i < n; i++ {
			me.logs[i], me.logs[i+me.rindex] = me.logs[i+me.rindex], gEmptyString
		}

		// reset read and write index
		me.windex, me.rindex = me.windex-me.rindex, 0
	}
}

func (me *tLoggingService) AllLogs() []string {
	return me.logs
}

var gLoggingService = newLoggingService()

func Logf(f string, args ...interface{}) {
	msg := fmt.Sprintf(f, args...)
	gLoggingService.Logf("%s %s", time.Now().Format("15:04:05.999999999"), msg)
}

func Any(msg string) bool {
	for _, it := range gLoggingService.AllLogs() {
		if strings.Contains(it, msg) {
			return true
		}
	}

	return false
}

func Count(msg string) int {
	sum := 0
	for _, it := range gLoggingService.AllLogs() {
		if strings.Contains(it, msg) {
			sum++
		}
	}
	return sum
}

func Verbose(v bool) {
	gLoggingService.Verbose(v)
}
